package main

import (
	"context"
	"errors"
	"fmt"
	"log"
	"net/http"
	"os"
	"os/signal"
	"syscall"

	"golang.org/x/sync/errgroup"
)

const (
	addr = "127.0.0.1:8080"
)

func main() {
	ctx, done := context.WithCancel(context.Background())
	g, gctx := errgroup.WithContext(ctx)

	g.Go(func() error {
		c := make(chan os.Signal, 1)
		signal.Notify(c, syscall.SIGTERM, syscall.SIGINT, syscall.SIGQUIT)

		select {
		case sig := <-c:
			log.Printf("received signal: %v\n", sig)
			done()
		case <-gctx.Done():
			log.Printf("signal errgroup done\n")
			return gctx.Err()
		}
		return nil
	})

	g.Go(func() error {
		s := http.Server{
			Addr:    addr,
			Handler: &handler{},
		}
		go func() {
			<-gctx.Done()

			log.Printf("server errgroup done\n")
			clean()
			if err := s.Shutdown(context.Background()); err != nil {
				log.Fatalf("shutdown error: %v\n", err)
			}
		}()

		if err := s.ListenAndServe(); err != nil {
			done()
			log.Println(err)
		}
		return nil
	})

	if err := g.Wait(); err != nil {
		if errors.Is(err, context.Canceled) {
			log.Println("context canceled")
		} else {
			log.Printf("errgroup recieved error: %v", err)
		}
	} else {
		log.Println("finish")
	}
}

type handler struct{}

func (h *handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintln(w, "hello world")
}

func clean() {
	log.Println("server shutdown clean")
}
